package com.gdth.http.method;

import com.gdth.exception.HttpException;
import com.gdth.rxjava.listener.SubscriberOnNextListener;
import com.gdth.rxjava.subscriber.ProgressSubscriber;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public class HttpMethodTest {

    public static final String BASE_URL = "https://api.douban.com/v2/movie/";

    private static final int DEFAULT_TIMEOUT = 10;

    private Retrofit retrofit;
    private MovieListener movieService;
    
    /**
     * 单例模式
     * @author arvin
     *
     */
    private static class SingletonHolder{
        private static final HttpMethodTest INSTANCE = new HttpMethodTest();
    }

    /**
     * 获取单例
     * @return
     */
    public static HttpMethodTest getInstance(){
        return SingletonHolder.INSTANCE;
    }

    //构造方法私有
    private HttpMethodTest() {
    	 OkHttpClient.Builder builder = new OkHttpClient.Builder();
         builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
         builder.addInterceptor(new Interceptor() {
             @Override
             public Response intercept(Chain chain) throws IOException {
                 Response response = chain.proceed(chain.request());
                 // Do anything with response here
                 return response;
             }
         });
        builder.dns(new EngDNS());
         builder.sslSocketFactory(httpsUtils.getSSLSocketFactory());
         builder.hostnameVerifier(httpsUtils.getHostnameVerifier());

        retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        movieService = retrofit.create(MovieListener.class);
    }

    /**
     * 
     * @param subscriber  由调用者传过来的观察者对象
     * @param start 起始位置
     * @param count 获取长度
     */
    public void getTopMovie(Subscriber<List<Subject>> subscriber, int start, int count){
        Observable<List<Subject>> observable = movieService.getTopMovie(start, count)
                .map(new HttpResultFuncTest<List<Subject>>());

        toSubscribe(observable, subscriber);
    }
    
    public void test(){
    	SubscriberOnNextListener<List<Subject>> mSubscriberOnNextListener = new SubscriberOnNextListener<List<Subject>>() {
            @Override
            public void onNext(List<Subject> subjects) {}

			@Override
			public void completed() {}

			@Override
			public void error(String arg0) {}
        };
        
        HttpMethodTest.getInstance().getTopMovie(new ProgressSubscriber<List<Subject>>(mSubscriberOnNextListener), 0, 10);
    }

    private <T> void toSubscribe(Observable<T> mObservable, Subscriber<T> mSubscriber){
    	mObservable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(mSubscriber);
    }

    /**
     * 用来统一处理Http的resultCode,并将HttpResult的Data部分剥离出来返回给subscriber
     *
     * @param <T>   Subscriber真正需要的数据类型，也就是Data部分的数据类型
     */
    private class HttpResultFuncTest<T> implements Func1<HttpResult<T>, T>{

        @Override
        public T call(HttpResult<T> httpResult) {
            if (httpResult.getCount() == 0) {
                throw new HttpException(100);
            }
            return httpResult.getSubjects();
        }
    }
    
    interface MovieListener {

//      @GET("top250")
//      Call<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);

//      @GET("top250")
//      Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);

//      @GET("top250")
//      Observable<HttpResult<List<Subject>>> getTopMovie(@Query("start") int start, @Query("count") int count);

      @GET("top250")
      Observable<HttpResult<List<Subject>>> getTopMovie(@Query("start") int start, @Query("count") int count);
  }
    
    class HttpResult<T> {

        private int count;
        private int start;
        private int total;
        private String title;

        private T subjects;


        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        public int getStart() {
            return start;
        }

        public void setStart(int start) {
            this.start = start;
        }

        public int getTotal() {
            return total;
        }

        public void setTotal(int total) {
            this.total = total;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }


        public T getSubjects() {
            return subjects;
        }

        public void setSubjects(T subjects) {
            this.subjects = subjects;
        }


        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("title=" + title + " count=" + count + " start=" + start);
            if (null != subjects) {
                sb.append(" subjects:" + subjects.toString());
            }
            return sb.toString();
        }
    }

    class Subject {

        private String id;
        private String alt;
        private String year;
        private String title;
        private String original_title;
        private List<String> genres;
        private List<Cast> casts;
        private List<Cast> directors;
        private Avatars images;

        @Override
        public String toString() {
            return "Subject.id=" + id
                    + " Subject.title=" + title
                    + " Subject.year=" + year
                    + " Subject.originalTitle=" + original_title + casts.toString() + directors.toString() + " | ";
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getAlt() {
            return alt;
        }

        public void setAlt(String alt) {
            this.alt = alt;
        }

        public String getYear() {
            return year;
        }

        public void setYear(String year) {
            this.year = year;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getOriginal_title() {
            return original_title;
        }

        public void setOriginal_title(String original_title) {
            this.original_title = original_title;
        }

        public List<String> getGenres() {
            return genres;
        }

        public void setGenres(List<String> genres) {
            this.genres = genres;
        }

        public List<Cast> getCasts() {
            return casts;
        }

        public void setCasts(List<Cast> casts) {
            this.casts = casts;
        }

        public List<Cast> getDirectors() {
            return directors;
        }

        public void setDirectors(List<Cast> directors) {
            this.directors = directors;
        }

        public Avatars getImages() {
            return images;
        }

        public void setImages(Avatars images) {
            this.images = images;
        }

        private class Cast{
            private String id;
            private String name;
            private String alt;
            private Avatars avatars;

            public String getId() {
                return id;
            }

            public void setId(String id) {
                this.id = id;
            }

            public String getName() {
                return name;
            }

            public void setName(String name) {
                this.name = name;
            }

            public String getAlt() {
                return alt;
            }

            public void setAlt(String alt) {
                this.alt = alt;
            }

            public Avatars getAvatars() {
                return avatars;
            }

            public void setAvatars(Avatars avatars) {
                this.avatars = avatars;
            }

            @Override
            public String toString() {
                return "cast.id=" + id + " cast.name=" + name + " | ";
            }
        }
    }
    
    private class Avatars{
        private String small;
        private String medium;
        private String large;

        public String getSmall() {
            return small;
        }

        public void setSmall(String small) {
            this.small = small;
        }

        public String getMedium() {
            return medium;
        }

        public void setMedium(String medium) {
            this.medium = medium;
        }

        public String getLarge() {
            return large;
        }

        public void setLarge(String large) {
            this.large = large;
        }
    }
}
